home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / program / 441 / gemfxm12 / minicolr.c < prev    next >
C/C++ Source or Header  |  1990-11-23  |  37KB  |  859 lines

  1.  
  2. /**************************************************************************
  3.  *
  4.  * mini_pallete - A little bitty control-panel-like color pallete acc.
  5.  *
  6.  *  Public Domain example program by Ian Lepore.
  7.  *
  8.  *  This is distributed as an example of how to write an accessory using
  9.  *  my AESFAST public domain GEM bindings.  This example uses a few of
  10.  *  the nifty utilities from AESFAST, but it's pretty much straightforward
  11.  *  window-handling code.
  12.  *
  13.  *  I built this beast because I have some graphics programs (Mandelbrot
  14.  *  fractal generators, a spyrograph program, etc), in which one would
  15.  *  naturally want to change the screen colors on the fly, but the %^$%#*&
  16.  *  system control panel covers the whole screen in low rez.  This acc
  17.  *  gives a nice itty-bitty moveable window with all the necessary color
  18.  *  controls in it.
  19.  *
  20.  *  This acc does not behave like the system control panel, in that it
  21.  *  will not reset the colors the application has set when you call it up.
  22.  *  On the other hand, the color changes you do with this accessory will 
  23.  *  not be saved if you use 'Save Desktop'. (Hint:  You would need to code
  24.  *  the shel_read() and shel_write() AES functions to make that work.  
  25.  *  Actually doing it is left as an excerise for the reader <grin>).
  26.  *
  27.  *  Also, the order of the colored boxes on the screen corresponds to the
  28.  *  TOS order of colors, not the VDI order.  (EG:  The foreground and
  29.  *  background colors are the first and last boxes, not the first two).
  30.  *
  31.  *  This code is pretty heavily commented.  Please excuse me if some of 
  32.  *  the comments seem obvious, but I figure the audience for this will 
  33.  *  include both beginning C programmers, and old-timers who just need to
  34.  *  see how my bindings work as opposed to other bindings.
  35.  *
  36.  *************************************************************************/
  37.  
  38. #include <gemfast.h>
  39. #include <osbind.h>
  40.  
  41. #ifndef TRUE
  42. #define TRUE  1
  43. #define FALSE 0
  44. #endif
  45.  
  46. #define Getcolor(a) ((int)(Setcolor((a), -1)))
  47.  
  48. #define graf_mkstate    graq_mstate    /* use Line-A mouse state call */
  49.  
  50. /**************************************************************************
  51.  *
  52.  * global vars (gee, there's not many of these for a change...)
  53.  *
  54.  *************************************************************************/
  55.  
  56. struct rgb_settings {
  57.         char red, grn, blu, filler;
  58.         } cur_setting;
  59.  
  60. int     coloridx = 0;                   /* default color index is # 0    */
  61.  
  62. #define WI_KIND         (MOVER|CLOSER|NAME)
  63. #define NO_WINDOW       -1
  64.  
  65. extern int gl_apid;                     /* defined in bindings library   */
  66.  
  67. int     menu_id ;                       /* our menu id                   */
  68. int     wi_handle;                      /* window handle                 */
  69. GRECT   treerect;                       /* object tree (in window) rect  */
  70.  
  71. char    menu_title[] = "  Mini Pallete  ";
  72. char    wind_title[] = " Mini Pallete ";
  73.  
  74. /**************************************************************************
  75.  *
  76.  * palttree - The color pallete dialog tree.
  77.  *
  78.  *  This is NOT the output from a resource editor (it was a long time ago,
  79.  *  but it's been pretty much re-done by hand).
  80.  *
  81.  *  About extended object types... 
  82.  *
  83.  *  The ob_type field is a word, but the AES only uses the lower byte of 
  84.  *  it.  It has become a sort of standard technique for programs to use
  85.  *  the upper byte for their own evil purposes.  (Really, the object 
  86.  *  structure should have had an 'ob_apspec' longword in it for the 
  87.  *  application's use).  Anyway, there is some discussion under the 
  88.  *  'find_boxchar' routine below on accessing arrays of objects in a tree
  89.  *  without being sure where the objects are in the tree array.  The
  90.  *  methods discussed below work fine for boxchar objects; the extended
  91.  *  object type can be used for other types of objects.  
  92.  *
  93.  *  For example, suppose you have 10 strings in a dialog box.  You want to
  94.  *  set the ob_spec pointers at runtime to correspond to the elements in
  95.  *  an array of strings you've defined in your program.  You can code a
  96.  *  lot of C statements using the hard-coded object names, but what if you
  97.  *  have 50 strings instead of 10?  More to the point, what if some hacker
  98.  *  edits the .RSC file and changes the order of the objects? Bombs, that's
  99.  *  what.  So, you can (with most resource editors) set the extended 
  100.  *  object type for the strings to the numbers 1-10, then at runtime you
  101.  *  can scan the tree looking for an object with an extended type of 1,
  102.  *  then set the first string pointer, then scan for 2, and so on.  Now,
  103.  *  no matter where those strings get moved to in the tree structure, they
  104.  *  will be found at runtime and pointers will be assigned properly.
  105.  *
  106.  *  Now that I've described this nifty string-thing, I should mention that
  107.  *  this program doesn't use that techique, as it contains no strings in
  108.  *  the dialog. 
  109.  * 
  110.  *  This program uses the extended object type to hold the TOS color index
  111.  *  value that corresponds to the colored box which is the object.  This
  112.  *  is due to the screwy way the ST maps TOS colors to VDI colors.  If you
  113.  *  compare the VDI/object color number in the ob_spec field to the extended
  114.  *  object type value, you'll see the translation table that maps TOS colors
  115.  *  to GEM colors.  For the ob_type values below which are not described
  116.  *  by name, the format is 0xcc14, where 'cc' is the TOS color number, and
  117.  *  '14' is a box type object.
  118.  *
  119.  *  The ob_spec field for box-like objects maps out as follows:
  120.  *   0xaabbcdef
  121.  *     |||||||+-- inside fill color
  122.  *     ||||||+--- fill pattern and opaque/transparent flag
  123.  *     |||||+---- text color
  124.  *     ||||+----- border color
  125.  *     ||++------ border thickness (neg = outside width, pos = inside width)
  126.  *     ++-------- ASCII character for boxchar objects, zero for other types
  127.  *
  128.  *  The two objects flagged as HIDETREE are no longer used, and I don't
  129.  *  want to rebuild the whole tree to remove them (and I've lost the
  130.  *  .RSC file that this source comes from).
  131.  *************************************************************************/
  132.  
  133. OBJECT  palttree[] = {
  134.  
  135. /*          type       flags   state   ob_spec     x       y       w        h   */
  136.  
  137. -1,  1, 35, G_BOX,     NONE,     0, 0x00000000L, 0x0000, 0x0000, 0x0212, 0x0506,
  138.  
  139.  2, -1, -1, G_BOXCHAR, HIDETREE, 0, 0x05FF1100L, 0x0000, 0x0000, 0x0000, 0x0000,
  140.  3, -1, -1, G_BOX,     HIDETREE, 0, 0x00FF1121L, 0x0000, 0x0000, 0x0000, 0x0000,
  141.  
  142.  7,  4,  6, G_IBOX,    NONE,     0, 0x00001101L, 0x0100, 0x0100, 0x0401, 0x0703,
  143.  5, -1, -1, G_BOXCHAR, NONE,     0, 0x52001100L, 0x0200, 0x0100, 0x0001, 0x0001,
  144.  6, -1, -1, G_BOXCHAR, NONE,     0, 0x47001100L, 0x0200, 0x0401, 0x0001, 0x0001,
  145.  3, -1, -1, G_BOXCHAR, NONE,     0, 0x42001100L, 0x0200, 0x0702, 0x0001, 0x0001,
  146.  
  147. 35,  8, 26, G_IBOX,    NONE,     0, 0x00001100L, 0x0501, 0x0200, 0x0210, 0x0603,
  148.  
  149. 17,  9, 16, G_IBOX,    NONE,     0, 0x00001100L, 0x0100, 0x0000, 0x0010, 0x0001,
  150. 10, -1, -1, G_BOXCHAR, NONE,     0, 0x30FF1100L,  0, 0, 2, 1,
  151. 11, -1, -1, G_BOXCHAR, NONE,     0, 0x31FF1100L,  2, 0, 2, 1,
  152. 12, -1, -1, G_BOXCHAR, NONE,     0, 0x32FF1100L,  4, 0, 2, 1,
  153. 13, -1, -1, G_BOXCHAR, NONE,     0, 0x33FF1100L,  6, 0, 2, 1,
  154. 14, -1, -1, G_BOXCHAR, NONE,     0, 0x34FF1100L,  8, 0, 2, 1,
  155. 15, -1, -1, G_BOXCHAR, NONE,     0, 0x35FF1100L, 10, 0, 2, 1,
  156. 16, -1, -1, G_BOXCHAR, NONE,     0, 0x36FF1100L, 12, 0, 2, 1,
  157.  8, -1, -1, G_BOXCHAR, NONE,     0, 0x37FF1100L, 14, 0, 2, 1,
  158.  
  159. 26, 18, 25, G_IBOX,    NONE,     0, 0x00001100L, 0x0100, 0x0301, 0x0010, 0x0001,
  160. 19, -1, -1, G_BOXCHAR, NONE,     0, 0x30FF1100L,  0, 0, 2, 1,
  161. 20, -1, -1, G_BOXCHAR, NONE,     0, 0x31FF1100L,  2, 0, 2, 1,
  162. 21, -1, -1, G_BOXCHAR, NONE,     0, 0x32FF1100L,  4, 0, 2, 1,
  163. 22, -1, -1, G_BOXCHAR, NONE,     0, 0x33FF1100L,  6, 0, 2, 1,
  164. 23, -1, -1, G_BOXCHAR, NONE,     0, 0x34FF1100L,  8, 0, 2, 1,
  165. 24, -1, -1, G_BOXCHAR, NONE,     0, 0x35FF1100L, 10, 0, 2, 1,
  166. 25, -1, -1, G_BOXCHAR, NONE,     0, 0x36FF1100L, 12, 0, 2, 1,
  167. 17, -1, -1, G_BOXCHAR, NONE,     0, 0x37FF1100L, 14, 0, 2, 1,
  168.  
  169.  7, 27, 34, G_IBOX,    NONE,     0, 0x00001100L, 0x0100, 0x0602, 0x0010, 0x0001,
  170. 28, -1, -1, G_BOXCHAR, NONE,     0, 0x30FF1100L,  0, 0, 2, 1,
  171. 29, -1, -1, G_BOXCHAR, NONE,     0, 0x31FF1100L,  2, 0, 2, 1,
  172. 30, -1, -1, G_BOXCHAR, NONE,     0, 0x32FF1100L,  4, 0, 2, 1,
  173. 31, -1, -1, G_BOXCHAR, NONE,     0, 0x33FF1100L,  6, 0, 2, 1,
  174. 32, -1, -1, G_BOXCHAR, NONE,     0, 0x34FF1100L,  8, 0, 2, 1,
  175. 33, -1, -1, G_BOXCHAR, NONE,     0, 0x35FF1100L, 10, 0, 2, 1,
  176. 34, -1, -1, G_BOXCHAR, NONE,     0, 0x36FF1100L, 12, 0, 2, 1,
  177. 26, -1, -1, G_BOXCHAR, NONE,     0, 0x37FF1100L, 14, 0, 2, 1,
  178.  
  179.  0, 36, 51, G_IBOX,    NONE,     0, 0x00001100L, 0x0000, 0x0104, 0x0212, 0x0302,
  180. 37, -1, -1, 0x0014,    NONE,     0, 0x00011170L, 512,    512,    2,      1,
  181. 38, -1, -1, 0x0814,    NONE,     0, 0x00000179L, 512,    769,    2,      1,
  182. 39, -1, -1, 0x0114,    NONE,     0, 0x00001172L, 1026,   512,    2,      1,
  183. 40, -1, -1, 0x0214,    NONE,     0, 0x00002173L, 1540,   512,    2,      1,
  184. 41, -1, -1, 0x0314,    NONE,     0, 0x00003176L, 7,      512,    2,      1,
  185. 42, -1, -1, 0x0414,    NONE,     0, 0x00000174L, 521,    512,    2,      1,
  186. 43, -1, -1, 0x0514,    NONE,     0, 0x00001177L, 1035,   512,    2,      1,
  187. 44, -1, -1, 0x0614,    NONE,     0, 0x00002175L, 1549,   512,    2,      1,
  188. 45, -1, -1, 0x0A14,    NONE,     0, 0x0000217BL, 1540,   769,    2,      1,
  189. 46, -1, -1, 0x0B14,    NONE,     0, 0x0000317EL, 7,      769,    2,      1,
  190. 47, -1, -1, 0x0C14,    NONE,     0, 0x0000017CL, 521,    769,    2,      1,
  191. 48, -1, -1, 0x0D14,    NONE,     0, 0x0000117FL, 1035,   769,    2,      1,
  192. 49, -1, -1, 0x0E14,    NONE,     0, 0x0000217DL, 1549,   769,    2,      1,
  193. 50, -1, -1, 0x0714,    NONE,     0, 0x00003178L, 16,     512,    2,      1,
  194. 51, -1, -1, 0x0914,    NONE,     0, 0x0000117AL, 1026,   769,    2,      1,
  195. 35, -1, -1, 0x0F14,    LASTOB,   0, 0x00003171L, 16,     769,    2,      1
  196. }; /* END of palttree[] */
  197.  
  198. /* resource set indicies (names) for objects in palttree */
  199.  
  200. #define PALTTREE 0  /* root */
  201. #define PALTPNUM 7  /* Parent box for all the intensity parents */
  202. #define PALTPRED 8  /* Parent box for the RED intensity numbers */
  203. #define PALTPGRN 17 /* Parent box for the GRN intensity numbers */
  204. #define PALTPBLU 26 /* Parent box for the BLU intensity numbers */
  205. #define PALTPCOL 35 /* Parent box for the color-selection boxes */
  206.  
  207. /**************************************************************************
  208.  *
  209.  * find_boxchar - Return the object index of a child boxchar with a given
  210.  *  letter in its box, or -1 if no matching object can be found.
  211.  *
  212.  *  Say what?  Well, this routine cruises through all the children of a 
  213.  *  given parent object, and for every boxchar type object found the char
  214.  *  in the box is compared to the char passed to this routine.  On the 
  215.  *  first match found, the object index of the matching object is returned.
  216.  *  (Note that the object type is masked with 0x00FF to strip out any
  217.  *  extended object type info, so that the object type compare will work).
  218.  *  
  219.  *  Why do this, you wonder?  Well, boxchar objects make great radio
  220.  *  buttons, especially for things like selecting a device, or in this 
  221.  *  case, a color intensity from 0-7.  In the case of device selection, 
  222.  *  you need to have buttons for A-P, but on most systems, there won't
  223.  *  be this many devices, and you'll need to set some of the buttons
  224.  *  (boxchars) to DISABLED.  Since you'll be doing this at runtime, you
  225.  *  need a way to find the corresponding button for each device.  It is
  226.  *  AN ABSOLUTE NO-NO to hard-code object indicies (names) or treat the 
  227.  *  objects as an array, because as soon as you do some user will come  
  228.  *  along with a resouce editor & re-sort your objects.  Then the user will
  229.  *  complain when s/he clicks on the drive A button, and drive B gets
  230.  *  formatted instead.
  231.  *
  232.  *************************************************************************/
  233.  
  234. int
  235. find_boxchar(tree, parent, boxchar)
  236.         register OBJECT *tree;
  237.         register int    parent;
  238.         register char   boxchar;
  239. {
  240.         register int kid;
  241.  
  242.         kid = tree[parent].ob_head;
  243.  
  244.         while ( (kid != parent) && (kid >= R_TREE) ) {
  245.                 if ((0x00FF & tree[kid].ob_type) == G_BOXCHAR) {
  246.                         if (boxchar == (char)(tree[kid].ob_spec >> 24)) {
  247.                                 return(kid);
  248.                         }
  249.                 }
  250.                 kid = tree[kid].ob_next;
  251.         }
  252.         return(-1);
  253. }
  254.  
  255. /**************************************************************************
  256.  *
  257.  * objxrb_which - Extended radio-button-finder... Find the object within
  258.  *  a given parent which has an object state matching the parm passed to
  259.  *  this routine. (The normal rb-finder looks only for SELECTED, this
  260.  *  routine can find CROSSED, etc).
  261.  *
  262.  *  This routine returns the object index of the first object that matches
  263.  *  the requested state, or -1 if no objects match.  Note that the object
  264.  *  does not have to be a radio button, in fact that isn't even checked.
  265.  *
  266.  *  The check is done via a bit-wise AND, so it *is not* possible to find 
  267.  *  an object only if it is both SELECTED and CHECKED (or whatever); in that
  268.  *  case, the routine will find the first object that's in *either* state.
  269.  *************************************************************************/
  270.  
  271. int
  272. objxrb_which(tree, parent, rbstate)
  273.         register OBJECT *tree;
  274.         register int    parent;
  275.         register char   rbstate;
  276. {
  277.         register int kid;
  278.  
  279.         kid = tree[parent].ob_head;
  280.  
  281.         while ( (kid != parent) && (kid >= R_TREE) ) {
  282.                 if (tree[kid].ob_state & rbstate) {
  283.                         return(kid);
  284.                 }
  285.                 kid = tree[kid].ob_next;
  286.         }
  287.         return(-1);
  288. }
  289.  
  290. /**************************************************************************
  291.  *
  292.  * rgb2color - convert cur_settings structure to a TOS color value.
  293.  *  This routine combines the separate ASCII RGB values into a single
  294.  *  integer RGB value in TOS format.  That is, if the cur_settings struct
  295.  *  contains '2', '6', and '3', this routine will return 0x0263.
  296.  *  
  297.  *************************************************************************/
  298.  
  299. int
  300. rgb2color()
  301. {
  302.         return ( ((cur_setting.red & 0x000F) << 8) | 
  303.                  ((cur_setting.grn & 0x000F) << 4) | 
  304.                   (cur_setting.blu & 0x000F) );
  305. }
  306.  
  307. /**************************************************************************
  308.  *
  309.  * color2rgb - convert a TOS color to characters in cur_settings.
  310.  *  This routine separates an integer TOS-format RGB value into 3 ASCII
  311.  *  characters in cur_settings.  If the TOS color is 0x0746, the structure
  312.  *  will contain '7', '4', and '6'.
  313.  *
  314.  *************************************************************************/
  315.  
  316. void
  317. color2rgb(color)
  318.         register int color;
  319. {
  320.         cur_setting.red = '0' + ( 0x000F & (color >> 8) );
  321.         cur_setting.grn = '0' + ( 0x000F & (color >> 4) );
  322.         cur_setting.blu = '0' + ( 0x000F &  color );
  323.  
  324. /**************************************************************************
  325.  *
  326.  * new_color - Change the current selected color box on the screen (like
  327.  *  a radio button), and set the new intensity settings (numbered boxes) 
  328.  *  to match the new active color box.
  329.  *
  330.  *  To show which color box is current, we set the ob_state to CROSSED
  331.  *  instead of SELECTED.  SELECTED will invert the color of the object,
  332.  *  which sorta defeats our purpose.  We don't have as much room on the
  333.  *  screen as the regular control panel, so we can't just make the box
  334.  *  a little bigger like it does.
  335.  *
  336.  *  If 'drawflag' is TRUE, the screen is updated with the state changes
  337.  *  (this is the normal state of affairs).  If the flag is FALSE, the
  338.  *  object states are set, but no screen work is done (this is for
  339.  *  initializing the dialog before it is displayed).
  340.  *************************************************************************/
  341.  
  342. void 
  343. new_color(newobject, drawflag)
  344.         register int newobject, drawflag;
  345. {
  346.         register OBJECT *ptree;
  347.         register int    wrkobject;
  348.         register int    curobject;
  349.         int             dmy;
  350.  
  351.         ptree = palttree;               /* quick register tree pointer */
  352.  
  353. /*
  354.  * figure out which is the currently-selected color box object. 
  355.  * if the current object is the same as the new object, the user is
  356.  * leaning on the mouse button; to avoid nasty object flashing on
  357.  * the screen in this case, just return.
  358.  */
  359.  
  360.         curobject = objxrb_which(ptree, PALTPCOL, CROSSED);
  361.         if (curobject == newobject) {
  362.                 return;
  363.         }
  364.         
  365. /*
  366.  * de-select the numbered radio buttons that show the intensity
  367.  * settings for the current color.  the 'if (-1 != ...)' logic prevents
  368.  * us from croaking the first time thru, since no buttons will be selected.
  369.  */
  370.  
  371.         if (-1 != (wrkobject = objrb_which(ptree, PALTPRED)))
  372.                 objst_change(ptree, wrkobject, ~SELECTED, drawflag);
  373.         if (-1 != (wrkobject = objrb_which(ptree, PALTPGRN)))
  374.                 objst_change(ptree, wrkobject, ~SELECTED, drawflag);
  375.         if (-1 != (wrkobject = objrb_which(ptree, PALTPBLU)))
  376.                 objst_change(ptree, wrkobject, ~SELECTED, drawflag);
  377.  
  378. /*
  379.  * de-select the current color box, select the new color box.  
  380.  * again the '-1' check is for the first time thru case.
  381.  */
  382.  
  383.         if (-1 != curobject) 
  384.                 objst_change(ptree, curobject, ~CROSSED, drawflag);
  385.         objst_change(ptree, newobject,  CROSSED, drawflag);
  386.  
  387. /*
  388.  * change our picture of what's current.  the TOS color index is encoded
  389.  * as the 'extended object type' of the color-box objects (see discussion 
  390.  * on this above, where palttree is defined).  the 'color2rgb' call will
  391.  * fill in the 'cur_settings' structure to represent the current intensity
  392.  * of the color just selected.  
  393.  */
  394.  
  395.         coloridx = 0x000F & (ptree[newobject].ob_type >> 8);
  396.         color2rgb( Getcolor(coloridx) );
  397.  
  398. /*
  399.  * select the appropriate numbered boxes to represent the color intensity
  400.  * settings for the newly-selected color. the 'cur_settings' array holds
  401.  * the ASCII representation of the RGB instensities.  this is done so that
  402.  * we can find the corresponding radio buttons (which are BOXCHAR objects)
  403.  * via the find_boxchar() function.
  404.  */
  405.  
  406.         wrkobject = find_boxchar(ptree, PALTPRED, cur_setting.red);
  407.         objst_change(ptree, wrkobject,  SELECTED, drawflag);
  408.         
  409.         wrkobject = find_boxchar(ptree, PALTPGRN, cur_setting.grn);    
  410.         objst_change(ptree, wrkobject,  SELECTED, drawflag);
  411.         
  412.         wrkobject = find_boxchar(ptree, PALTPBLU, cur_setting.blu);
  413.         objst_change(ptree, wrkobject,  SELECTED, drawflag);
  414.  
  415. /* all done */
  416.  
  417. }
  418.      
  419. /**************************************************************************
  420.  *
  421.  * new_settings - Process a click in a numbered box of the dialog, and
  422.  *  change the color intensity in the TOS color pallete correspondingly.
  423.  *
  424.  *************************************************************************/
  425.  
  426. void
  427. new_settings(newobject)
  428. {
  429.         char boxchar;
  430.         int  curparent,
  431.              curobject;
  432.  
  433. /*
  434.  * figure out what's being changed.  the 'curparent' value will tell us
  435.  * whether it's the R, G, or B value.  the 'curobject' is used to detect
  436.  * whether the user is leaning on the mouse (curobject == newobject);
  437.  * in this case we exit without taking any action, to avoid nasty graphic
  438.  * flashing on the screen.
  439.  *
  440.  */
  441.  
  442.         curparent = obj_parent(palttree, newobject);
  443.         curobject = objrb_which(palttree, curparent);
  444.         
  445.         if (curobject == newobject) {
  446.                 return;
  447.         }
  448.         
  449. /*
  450.  * the displayed intensity buttons are G_BOXCHAR objects, with the chars
  451.  * ranging from '0' - '7' for each color.  we pluck the displayed char 
  452.  * out of the ob_spec value in the tree (ob_spec for boxchars looks like
  453.  * 0xCCnnnnnn), and we plug the char right into the 'cur_settings' array,
  454.  * still in its ASCII form. 
  455.  */
  456.  
  457.         boxchar = (char)(palttree[newobject].ob_spec >> 24);
  458.  
  459.         switch (curparent) {
  460.                 case PALTPRED:
  461.                         cur_setting.red = boxchar;
  462.                         break;
  463.                 case PALTPGRN:
  464.                         cur_setting.grn = boxchar;
  465.                         break;
  466.                 case PALTPBLU:
  467.                         cur_setting.blu = boxchar;
  468.                         break;
  469.         }  
  470.         
  471. /* 
  472.  * now that the 'cur_settings' array contains the new intensity setting,
  473.  * call 'rgb2color' to convert the ASCII values to a single binary TOS
  474.  * color value, then call the TOS 'Setcolor' function to make the change.
  475.  */
  476.  
  477.         Setcolor( coloridx, rgb2color() );
  478.  
  479. /*
  480.  * de-select the old intensity setting, select the new one...
  481.  */
  482.         objst_change(palttree, curobject, ~SELECTED, TRUE);
  483.         objst_change(palttree, newobject,  SELECTED, TRUE); 
  484.  
  485. /* all done */
  486.  
  487. }
  488.  
  489. /**************************************************************************
  490.  *
  491.  * prg_init - Mundane program init stuff.
  492.  *  The only item of note here is a call to 'rsc_treefix'.  This is a
  493.  *  routine from the AESFAST library that will do an rsrc_obfix() call for
  494.  *  each object in a tree.  It's used only for resource trees buried in 
  495.  *  source code, if the resource file is loaded, the rsrc_load() call
  496.  *  handles the object x/y/w/h fixup internally.
  497.  *
  498.  *  Oh yeah -- I discovered an interesting problem coding this:  If the
  499.  *  'menu_register' call is not the first AES call following the appl_init
  500.  *  the accessory sometimes doesn't show up on the DESK menu until
  501.  *  after you've run some other GEM program.  This is consistant with the
  502.  *  rules of AES multitasking:  your program can be swapped out on ANY
  503.  *  AES call, not just when you do an evnt_???? call.  It just isn't 
  504.  *  mentioned in any of the docs I have.
  505.  *************************************************************************/
  506.  
  507. prg_init()
  508. {
  509.         appl_init();
  510.  
  511.         menu_id = menu_register(gl_apid, menu_title);
  512.         
  513.         rsc_treefix(palttree);
  514.  
  515.         form_center(palttree, &treerect.g_x, &treerect.g_y, 
  516.                               &treerect.g_w, &treerect.g_h);
  517.  
  518.         new_color(0, FALSE);
  519.  
  520.         wi_handle = NO_WINDOW;
  521. }
  522.  
  523. /**************************************************************************
  524.  *
  525.  * open_window 
  526.  *   Create and open the window, if it's not open already.
  527.  *
  528.  *   If the window is already open, it may be hidden from the user by an
  529.  *   overlapping window, and the only way to get us back may be to
  530.  *   click on us again in the DESK menu.  In this case, we just ask
  531.  *   the AES to bring our window back to the top.
  532.  *
  533.  *   Before opening the window, we calculate its size and location (total 
  534.  *   size, including its borders & controls) based upon the current size 
  535.  *   and location of the pallete object tree.  The first time the window
  536.  *   opens, this will be the center of the screen, because we do a 
  537.  *   form_center on the pallete tree.  For subsequent calls, we show up
  538.  *   wherever we were last on the screen.
  539.  *
  540.  *   We also set the window title bar here, before opening the window.   
  541.  *************************************************************************/
  542.  
  543. open_window()
  544. {
  545.         GRECT windrect;
  546.         
  547.         if (wi_handle == NO_WINDOW) {
  548.         
  549.                 wind_calc(WC_BORDER, WI_KIND, treerect, 
  550.                            &windrect.g_x, &windrect.g_y,
  551.                            &windrect.g_w, &windrect.g_h);
  552.                            
  553.                 wi_handle = wind_create(WI_KIND, windrect);
  554.                 
  555.                 wind_set(wi_handle, WF_NAME, wind_title, 0L);
  556.                 
  557.                 wind_open(wi_handle, windrect);
  558.         } 
  559.         else {
  560.                 wind_set(wi_handle, WF_TOP, 0L, 0L);
  561.         }
  562. }
  563.  
  564. /**************************************************************************
  565.  *
  566.  * close_window
  567.  *  Close and delete the window, if it's open.
  568.  *************************************************************************/
  569.  
  570. close_window()
  571. {
  572.         if (wi_handle != NO_WINDOW) {       
  573.                 wind_close(wi_handle);
  574.                 wind_delete(wi_handle);
  575.                 wi_handle = NO_WINDOW;
  576.         }
  577. }
  578.  
  579. /**************************************************************************
  580.  *
  581.  * do_redraw - Process redraw list.
  582.  *  Ok, let's see if I can explain this better than the DRI books do...
  583.  *
  584.  *  After somebody has munged up the screen (say with a dialog box), they
  585.  *  send a redraw request to the whole world.  The redraw request comes
  586.  *  from one of two sources:  1) Somebody does a form_dial(FMD_FINISH...)
  587.  *  call, or 2) Somebody does a wind_close() call.  (Ummm, ok, so there's
  588.  *  other sources, now that I think of it, like windows being moved or
  589.  *  sized).  Anyway, when AES sends out a redraw request, it sends it to
  590.  *  everybody who owns a window, and what it sends is the full x/y/w/h
  591.  *  values of the area of the screen to restore.
  592.  *
  593.  *  The area to be restored may or may not overlap any of the windows you
  594.  *  have open on the screen.  The AES can provide you with a list of the
  595.  *  visible rectangles that comprise your window(s).  (Remember that not
  596.  *  all of a window you have open may be visible).  So, to process a 
  597.  *  redraw, you have to ask AES for each of the visible rectangles, and
  598.  *  for each one returned, see if it overlaps the screen area to be redrawn.
  599.  *
  600.  *  There is a library routine in AESFAST called 'rc_intersect' that will
  601.  *  compute the intersecting portion of 2 rectangular screen areas. If 
  602.  *  the rectangles don't overlap at all, it will return FALSE.  Thus, we
  603.  *  have a loop in which we ask the AES for each rectangle, and we check
  604.  *  it against the redraw rectangle, and if there is some overlap, we call
  605.  *  the routine which actually draws the window contents, passing that
  606.  *  routine the boundries of the intersecting rectangle.  The looping 
  607.  *  continues until the AES returns us a rectangle from the list that has
  608.  *  zero height and width.
  609.  *
  610.  *************************************************************************/
  611.  
  612. do_redraw(updtrect)
  613.         GRECT updtrect;         /* the full area that needs updating */
  614. {
  615.         GRECT listrect;         /* one of our visible areas */
  616.  
  617.         wind_get(wi_handle, WF_FIRSTXYWH,
  618.                   &listrect.g_x, &listrect.g_y, 
  619.                   &listrect.g_w, &listrect.g_h);
  620.                   
  621.         while ( listrect.g_w && listrect.g_h ) {
  622.                 if ( rc_intersect(&updtrect, &listrect) ) {
  623.                         draw_window(listrect);
  624.                 }
  625.                 wind_get(wi_handle, WF_NEXTXYWH, 
  626.                           &listrect.g_x, &listrect.g_y,
  627.                           &listrect.g_w, &listrect.g_h);
  628.         }
  629. }
  630.  
  631.  
  632. /**************************************************************************
  633.  *
  634.  * draw_window - Draw the contents of the window, with clipping.
  635.  *  In this case, we just do an objc_draw call on our tree, passing the
  636.  *  clipping rectangle we receive along to the objc_draw.
  637.  *
  638.  *************************************************************************/
  639.  
  640.  
  641. draw_window(cliprect)
  642. GRECT cliprect;
  643.         objc_draw(palttree, R_TREE, MAX_DEPTH, cliprect);
  644. }
  645.  
  646.  
  647. /**************************************************************************
  648.  *
  649.  * just for grins dept:  This is what a draw_window() routine might
  650.  *  look like if the window was not based upon an object tree.  I'm
  651.  *  assuming a really stupid window which has a circle and some blit-based
  652.  *  graphics in it.
  653.  *
  654.  *************************************************************************/
  655.  
  656. #if 0                           /* don't really compile this code... */
  657.  
  658. draw_vwindow(cliprect)
  659. GRECT cliprect;
  660. {
  661.         long  dmyfdb = 0L;
  662.         VRECT vdiclip;
  663.         struct {
  664.                 VRECT blit1rect;
  665.                 VRECT blit2rect;
  666.                 } blitarea;
  667.  
  668. /*
  669.  * convert the GRECT-type clipping rectangle (x/y/w/h) to a VRECT-type
  670.  * rectangle (x1,y1,x2,y2).  set the VDI clipping area, and call the
  671.  * VDI circle function.
  672.  */
  673.  
  674.         rc_gtov(&cliprect, &vdiclip);
  675.         vs_clip(vdi_handle, &vdiclip, TRUE);
  676.         v_circle(vdi_handle, x, y, r);
  677.  
  678. /*
  679.  * for the blit, I'm assuming the blit buffer is a 32k screen image, and
  680.  * you just want to blit the corresponding area back onto the screen. the
  681.  * MFDB structure describing the blit buffer has already been filled out
  682.  * before this routine is ever called <grin>.  (Obscure Fact Dept: for
  683.  * blitting to the screen, a full MFDB is not needed...one only needs
  684.  * a longword of zeroes, which is a key telling VDI to use the screen as
  685.  * the destination.)
  686.  *
  687.  * the blit routine needs a VRECT describing the source and another 
  688.  * describing the destination, and the docs always describe this as a 
  689.  * 'pxy array', so everybody defines pxy[8] and tediously loads all the
  690.  * array elements with x/y values.  structures in C place all the elements
  691.  * contiguously, so the 'blitarea' structure defined above is pretty much
  692.  * equivelent to using a pxy array, except the code is now *much* more
  693.  * readable.
  694.  */
  695.         
  696.         rc_gtov(&cliprect, &blitarea.blit1rect);
  697.         rc_gtov(&cliprect, &blitarea.blit2rect);
  698.         vro_cpyfm(vdi_handle, S_ONLY, &blitarea, &sourcefdb, &dmyfdb);
  699. }
  700.  
  701. #endif
  702.  
  703. /**************************************************************************
  704.  *
  705.  * do_msg - Handle a message returned by evnt_multi().
  706.  *  This is pretty standard message handling for an accessory.  One item of
  707.  *  interest I discovered when building this is that you should *not* 
  708.  *  attempt to close any open windows when you get an AC_CLOSED message.
  709.  *  This message apparently tells you that your windows have already been
  710.  *  closed and deleted, and you should just mark your window handle(s) as
  711.  *  no longer valid.
  712.  *
  713.  *  The only piece of weirdness here is the WM_MOVED case.  The window
  714.  *  provides a frame for our object tree, so when it gets moved, we have
  715.  *  to update the ob_x and ob_y values in the pallete tree to match (so
  716.  *  that objc_draw commands will draw inside the window's work area).
  717.  *  The values in msgbuf reflect the new x/y/w/h of the window's total 
  718.  *  size (borders and controls included).  We have the option of changing
  719.  *  these values (like snapping to a character grid or whatever) or even
  720.  *  of ignoring them, but in this instance we don't care about any of that
  721.  *  so we just tell AES to use the values directly.  After doing the 
  722.  *  wind_set call to set the new location of the window, we call wind_get
  723.  *  to find out the new x/y/w/h of the work area of the window, so that
  724.  *  we can reposition the object tree.  We don't have to redraw the
  725.  *  window contents during WM_MOVED processing, because the AES will blit
  726.  *  the window contents for us if it can.  If not all of the window can
  727.  *  be blitted, the AES will send redraw messages to us, and we'll get
  728.  *  them on the next iteration of the evnt_multi loop.
  729.  *************************************************************************/
  730.  
  731. do_msg(msgbuf)
  732. register int msgbuf[];
  733. {
  734.  
  735.         switch (msgbuf[0]) {
  736.  
  737.                 case AC_OPEN:
  738.                         if (msgbuf[4] == menu_id) 
  739.                                 open_window();
  740.                         break;
  741.  
  742.                 case AC_CLOSE:
  743.                         wi_handle = NO_WINDOW;
  744.                         break;
  745.  
  746.                 case WM_REDRAW:
  747.                         if (msgbuf[3] == wi_handle)
  748.                                 do_redraw(msgbuf[4], msgbuf[5],
  749.                                           msgbuf[6], msgbuf[7]);
  750.                         break;
  751.  
  752.                 case WM_NEWTOP:
  753.                 case WM_TOPPED:
  754.                         if (msgbuf[3] == wi_handle) 
  755.                                 wind_set(wi_handle, WF_TOP, 0L, 0L);
  756.                         break;
  757.  
  758.                 case WM_CLOSED:
  759.                         close_window();
  760.                         break;
  761.  
  762.                 case WM_MOVED:
  763.                         if(msgbuf[3] == wi_handle) {
  764.                                 wind_set(wi_handle, WF_CURRXYWH, 
  765.                                           msgbuf[4], msgbuf[5],
  766.                                           msgbuf[6], msgbuf[7]);
  767.                                 wind_get(wi_handle, WF_WORKXYWH,
  768.                                           &treerect.g_x, &treerect.g_y, 
  769.                                           &treerect.g_w, &treerect.g_h);
  770.                                 palttree->ob_x = treerect.g_x;
  771.                                 palttree->ob_y = treerect.g_y;                 
  772.                         }
  773.                         break;
  774.  
  775.                 } /* END switch (msgbuf[0]) */
  776. }
  777.  
  778. /**************************************************************************
  779.  *
  780.  * do_btn - Handle a button click within our window.
  781.  *  Do a graf_mkstate() call to get the most-current location of the
  782.  *  mouse.  Call objc_find() to see if the mouse is located over an object
  783.  *  in our tree.  If so, we determine the parent of the tree.  If the
  784.  *  parent is one of the boxes which holds our various radio buttons, we
  785.  *  go process the button, as appropriate.  If it is over an object of
  786.  *  ours, but not within a parent box, we just ignore the click.
  787.  *
  788.  *************************************************************************/
  789.  
  790. do_btn()
  791. {
  792.         int mouse_x;
  793.         int mouse_y;
  794.         int selobject;
  795.         int dmy;
  796.         
  797.         graf_mkstate(&mouse_x, &mouse_y, &dmy, &dmy);
  798.  
  799.         selobject = objc_find(palttree, R_TREE, MAX_DEPTH, mouse_x, mouse_y);
  800.  
  801.         if (selobject != -1) {
  802.                 switch (obj_parent(palttree, selobject)) {
  803.                         case PALTPCOL: 
  804.                                 new_color(selobject, TRUE);
  805.                                 break;
  806.                         case PALTPRED: 
  807.                         case PALTPGRN:
  808.                         case PALTPBLU:
  809.                                 new_settings(selobject);
  810.                                 break;
  811.                 } /* END switch (obj_parent(selobject)) */
  812.         } /* END if (selobject != -1) */
  813. }
  814.  
  815. /**************************************************************************
  816.  *
  817.  * main routine
  818.  *  Call the init routine, then fall into a do-forever evnt_multi() loop.
  819.  *
  820.  *************************************************************************/
  821.  
  822. main()
  823. {
  824.         int dmy;
  825.         int event;
  826.         int msgbuf[8];
  827.         
  828.         prg_init();
  829.  
  830.         while (TRUE) {
  831.                 event = evnt_multi(
  832.                          MU_MESAG | MU_BUTTON,
  833.                          1,1,1,               /* mbclicks, mbmask, mbstate*/
  834.                          0,0,0,0,0,           /* Mouse event rectangle 1  */
  835.                          0,0,0,0,0,           /* Mouse event rectangle 2  */
  836.                          msgbuf,              /* Message buffer           */
  837.                          0,0,                 /* timer event, time = 0,0  */
  838.                          &dmy, &dmy,          /* Mouse x & y at event     */
  839.                          &dmy,                /* Mouse button at event    */
  840.                          &dmy,                /* Keystate at event        */           
  841.                          &dmy,                /* Keypress at event        */
  842.                          &dmy);               /* Mouse click count        */
  843.  
  844.                 wind_update(BEG_UPDATE);
  845.  
  846.                 if (event & MU_MESAG)
  847.                         do_msg(msgbuf);
  848.                 
  849.                 if (event & MU_BUTTON) 
  850.                         do_btn();
  851.                 
  852.                 wind_update(END_UPDATE);
  853.         
  854.         } /* END while (TRUE) */
  855. }
  856.  
  857.